const express = require('express')
const bodyParser = require('body-parser')
const multiparty = require('multiparty')
const SparkMD5 = require('spark-md5');
const fs = require('fs');
const PORT = 8888
const app = express()

// 处理post请求体数据
app.use(bodyParser.urlencoded({
  extended: false,
  limit: '1024mb'
}))
app.use(bodyParser.json({
  limit: '1024mb'
}));

// 设置上传目录
const uploadDir = `${__dirname}/upload`

// 定义公共上传的方法
function handleMultiparty (req, res, tem = false) {
  return new Promise((resolve, reject) => {
    const options = {
      maxFieldsSize: 200 * 1024 * 1024
    }
    if (!tem) {
      options.uploadDir = uploadDir
    }
    const form = new multiparty.Form(options)
    form.parse(req, function (err, fields, files) {
      if (err) {
        res.send({
          code: 1,
          message: JSON.stringify(err)
        })
        reject(err);
        return false;
      }
      resolve({
        fields, 
        files,
      })
    })
  })
}

// 基于form-data上传数据
app.post('/upload1', async(req, res) => {
  const { files, fields} = await handleMultiparty(req, res);
  console.log(fields, 'formData中携带的参数');
  const file = files.file[0];
  res.send({
    code: 0,
    originalFilename: file.originalFilename,
    path: file.path.replace(__dirname, `http://127.0.0.1:${PORT}`)
  })
})

// 使用base64上传文件
app.post('/upload2', async(req, res) => {
  const {chunk, filename, title} = req.body;
  console.log(title)
  // 将前端传递过来的bs64转换为buffer
  const chunk1 = decodeURIComponent(chunk);
  const chunk2 = chunk1.replace(/^data:image\/\w+;base64,/, "");
  const chunk3 = Buffer.from(chunk2, 'base64');
  // 存储文件到服务器端
  const spark = new SparkMD5.ArrayBuffer();
  const suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1]; // 文件的后缀名
  spark.append(chunk3);
  const path = `${uploadDir}/${spark.end()}.${suffix}`;
  fs.writeFileSync(path, chunk3);
  res.send({
    code: 0,
    originalFilename: filename,
    path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
  });
});

// 切片上传
app.post('/upload3', async (req, res) => {
  const {fields,files} = await handleMultiparty(req, res, true);
  const [chunk] = files.chunk;
  const [filename] = fields.filename;
  // 获取上传文件的hash
  const hash = /([0-9a-zA-Z]+)_\d+/.exec(filename)[1];
  const dir = `${uploadDir}/${hash}`;
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir);
  }
  const path = `${dir}/${filename}`;
  fs.access(path, async err => {
    // 如果已经存在了就不做任何处理
    if (!err) {
      res.send({
        code: 0,
        path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
      })
    }
    // 测试上传需要时间,手动延迟
    await new Promise(resolve => {
      setTimeout(() => {
        resolve();
      }, 100);
    });
    // 不存在的时候就创建
    const readStream = fs.createReadStream(chunk.path);
    const writeStream = fs.createWriteStream(path);
    readStream.pipe(writeStream);
    readStream.on('end', function() {
      fs.unlinkSync(chunk.path);
      res.send({
        code: 0,
        path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
      });
    })
  })
});

// 大文件上传后
app.get('/merge',(req, res) => {
  const { hash } = req.query;
  const path = `${uploadDir}/${hash}`;
  const fileList = fs.readdirSync(path);
  let suffix = null;
  fileList.sort((a, b) => {
    const reg = /_(\d+)/;
    return reg.exec(a)[1] - reg.exec(b)[1];
  }).forEach(item => {
    !suffix ? suffix = /\.([0-9a-zA-Z]+)$/.exec(item)[1] : null;
    // 写入文件
    fs.appendFileSync(`${uploadDir}/${hash}.${suffix}`, fs.readFileSync(`${path}/${item}`));
    // 删除文件
    fs.unlinkSync(`${path}/${item}`);
  });
  fs.rmdirSync(path);
  res.send({
    code: 0,
    path: `http://127.0.0.1:${PORT}/upload/${hash}.${suffix}`
  });
})


app.listen(PORT, () => {
  console.log(`服务已经启动,请访问localhost:${PORT}`)
})
